<template>
	<view class="e-album">
		<view class="e-album__row" :id="index === 0 ? elId : undefined " :ref="index === 0 ? 'albumRowRef' : undefined "
			v-for="(arr, index) in showUrls" :key="index">
			<view class="e-album__row__wrapper" v-for="(item, index1) in arr" :key="index1"
				:style="[imageStyle(index + 1, index1 + 1)]" @tap="onPreviewTap(item)">
				<image :src="getSrc(item)" :mode="
                        props.urls.length === 1
                            ? imageHeight > 0
                                ? props.singleMode
                                : 'widthFix'
                            : props.multipleMode
                    " :style="[
                        {
                            width: imageWidth,
                            height: addUnit(imageHeight)
                        }
                    ]"></image>
				<view v-if="
                        props.showMore &&
                        props.urls.length > props.rowCount * showUrls.length &&
                        index === showUrls.length - 1 &&
                        index1 === showUrls[showUrls.length - 1].length - 1
                    " class="e-album__row__wrapper__text">
					<e-text :text="`+${props.urls.length - props.maxCount}`" color="#fff" :size="props.multipleSize * 0.3" align="center"
						customStyle="justify-content: center"></e-text>
				</view>
			</view>
		</view>
	</view>
</template>

<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * Album 相册
	 * @description 本组件提供一个类似相册的功能，让开发者开发起来更加得心应手。减少重复的模板代码
	 * @tutorial https://www.uviewui.com/components/album.html
	 *
	 * @property {Array}           urls             图片地址列表 Array<String>|Array<Object>形式
	 * @property {String}          keyName          指定从数组的对象元素中读取哪个属性作为图片地址
	 * @property {String | Number} singleSize       单图时，图片长边的长度  （默认 180 ）
	 * @property {String | Number} multipleSize     多图时，图片边长 （默认 70 ）
	 * @property {String | Number} space            多图时，图片水平和垂直之间的间隔 （默认 6 ）
	 * @property {String}          singleMode       单图时，图片缩放裁剪的模式 （默认 'scaleToFill' ）
	 * @property {String}          multipleMode     多图时，图片缩放裁剪的模式 （默认 'aspectFill' ）
	 * @property {String | Number} maxCount         取消按钮的提示文字 （默认 9 ）
	 * @property {Boolean}         previewFullImage 是否可以预览图片 （默认 true ）
	 * @property {String | Number} rowCount         每行展示图片数量，如设置，singleSize和multipleSize将会无效	（默认 3 ）
	 * @property {Boolean}         showMore         超出maxCount时是否显示查看更多的提示 （默认 true ）
	 *
	 * @event    {Function}        albumWidth       某些特殊的情况下，需要让文字与相册的宽度相等，这里事件的形式对外发送  （回调参数 width ）
	 * @example <e-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></e-album>
	 */
	export default defineComponent({
		name: "e-album",
		mixins: [mpMixin],
	})
</script>

<script lang="ts" setup>
	import {
		ref,
		computed,
		watch,
		toRefs,
		getCurrentInstance,
	} from 'vue'
	import {
		albumProps,
		albumEmits
	} from './props';
	import {
		addUnit
	} from '../../libs/utils/_utils'
	import {
		sleep,
		isObj,
		isArray,
		getProperty,
		getRect,
		getNvueRect,
		nanoid
	} from '../../libs/utils'
	import type {
		StyleProperties
	} from "../../libs/tokens";
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";

	const {
		album: albumDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(albumProps)

	const props = useDefaultProps<DefaultProps['album']>(_props, albumDefaultProps);
	const emit = defineEmits(albumEmits)

	const ctx = getCurrentInstance()

	const singleWidth = ref(0)// 单图的宽度
	const singleHeight = ref(0)// 单图的高度
	const singlePercent = ref(0.6)// 单图时，如果无法获取图片的尺寸信息，让图片宽度默认为容器的一定百分比

	// 将数组划分为二维数组
	const showUrls = computed(() => {
		const arr : Array<typeof props.value.urls> = []
		props.value.urls?.map((item, index) => {
			// 限制最大展示数量
			if (index + 1 <= (props.value.maxCount as number)) {
				// 计算该元素为第几个素组内
				const itemIndex = Math.floor(index / (props.value.rowCount as number))
				// 判断对应的索引是否存在
				if (!arr[itemIndex]) {
					arr[itemIndex] = []
				}
				(arr[itemIndex] as any[]).push(item as any)
			}
		})
		return arr

	})

	const imageWidth = computed(() => {
		return addUnit(
			props.value.urls?.length === 1 ? singleWidth.value : props.value.multipleSize
		)
	})
	const imageHeight = computed(() => {
		return  props.value.urls?.length === 1 ? singleHeight.value : props.value.multipleSize 
	})

	const imageStyle = (index1 : number, index2 : number) => {

		const { space, rowCount } = props.value,
			rowLen = showUrls.value.length;

		const style : StyleProperties = {
			marginRight: addUnit(space),
			marginBottom: addUnit(space)
		}
		// 如果为最后一行，则每个图片都无需下边框
		if (index1 === rowLen) style.marginBottom = 0
		// 每行的最右边一张和总长度的最后一张无需右边框
		if (
			index2 === rowCount ||
			(index1 === rowLen &&
				index2 === showUrls.value[index1 - 1]?.length)
		)
			style.marginRight = 0
		return style

	}
	// 获取图片的路径
	const getSrc = (item : Record<string, any> | string) : string => {
		return isObj(item) ? (getProperty(item, props.value.keyName) || item.src) : item

	}
	
	// 预览图片
	const onPreviewTap = (item:Record<string, any> | string) => {
		if(!props.value.previewFullImage)return 
		
		const urls = props.value?.urls?.map((items) => {
			return getSrc(items)
		}) || []
		uni.previewImage({
			current:getSrc(item),
			urls
		})
	}

	// 单图时，获取图片的尺寸
	// 在小程序中，需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
	// 在没有添加的情况下，让单图宽度默认为盒子的一定宽度(singlePercent)
	const getImageRect = () => {
		const src = getSrc(props.value.urls ? props.value.urls[0] : '')
		uni.getImageInfo({
			src,
			success: (res) => {
				// 判断图片横向还是竖向展示方式
				const isHorizotal = res.width >= res.height
				singleWidth.value = isHorizotal
					? (props.value.singleSize as number)
					: (res.width / res.height) * (props.value.singleSize as number)
				singleHeight.value = !isHorizotal
					? (props.value.singleSize as number)
					: (res.height / res.width) * singleWidth.value
			},
			fail: () => {
				getComponentWidth()
			}
		})
	}
	const elId = ref(nanoid(21, true))
	const albumRowRef = ref()
	// 获取组件的宽度
	const getComponentWidth = async () => {
		// 延时一定时间，以获取dom尺寸
		await sleep(30)
		// #ifndef APP-NVUE
		getRect(ctx, '.e-album__row').then((size) => {
			singleWidth.value = size.width! * singlePercent.value
		})
		// #endif
	
	// #ifdef APP-NVUE
		
		getNvueRect(albumRowRef.value).then((size) => {
			singleWidth.value = size.width! * singlePercent.value
		})
		// #endif
	}

	watch(() => props.value.urls, (v) => {
		if (!isArray(v)) return
		let width = 0
		if (v.length === 1) {
			getImageRect()
			width = singleWidth.value
		} else {
			width = (showUrls.value[0]?.length||0) * (props.value.multipleSize as number) +
				(props.value.space as number) * ((showUrls.value[0]?.length||0) - 1)
		}
		emit('albumWidth', width)


	}, {
		immediate: true,
		deep: true
	})
</script>
<style lang="scss" scoped>
	@import "../../libs/theme/album.scss";
</style>
